package com.ysu.zyw.svc;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import com.ysu.zyw.common.Constant;
import com.ysu.zyw.dao.ReimbursementBusinessMapper;
import com.ysu.zyw.dao.UserMapper;
import com.ysu.zyw.entity.ReimbursementBusiness;
import com.ysu.zyw.entity.User;
import com.ysu.zyw.tool.ThreeTuple;
import com.ysu.zyw.tool.Tuple;
import com.ysu.zyw.web.vo.HistoricTaskVo;
import com.ysu.zyw.web.vo.ReimbursementVo;
import com.ysu.zyw.web.vo.TaskVo;

@Service
public class ActivitiService {

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private TaskService taskService;

    @Resource
    private HistoryService historyService;

    @Resource
    private UserService userService;

    @Resource
    private ReimbursementBusinessMapper reimbursementBusinessMapper;

    @Resource
    private UserMapper userMapper;

    public void deploy() {
        repositoryService.createDeployment().addClasspathResource("diagram/ReimbursementProcess.bpmn")
                .addClasspathResource("diagram/ReimbursementProcess.png")
                .name("部署 - " + ((int) (Math.random() * 100000)) + " - " + new Date()).deploy();
    }

    public Tuple<Long, Long> getActivitiDeploymentCount() {
        return new Tuple<Long, Long>(repositoryService.createDeploymentQuery().count(),
                repositoryService.createProcessDefinitionQuery().count());
    }

    /**
     * 获取流程部署/流程部署对应的资源名列表/流程部署对应的流程定义列表
     */
    public List<ThreeTuple<Deployment, List<String>, List<ProcessDefinition>>> getActivitiDeploymentList() {
        List<Deployment> deploymentList = repositoryService.createDeploymentQuery().orderByDeploymenTime().desc()
                .list();

        List<ThreeTuple<Deployment, List<String>, List<ProcessDefinition>>> deploymentThreeTupleList = deploymentList
                .stream().collect(Collectors.mapping(deployment -> {

                    String deploymentId = deployment.getId();

                    List<String> resourceNameList = repositoryService.getDeploymentResourceNames(deploymentId).stream()
                            .filter(resourceName -> resourceName.endsWith("png")).collect(Collectors.toList());

                    List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery()
                            .deploymentId(deploymentId).orderByProcessDefinitionVersion().desc().list();

                    return new ThreeTuple<Deployment, List<String>, List<ProcessDefinition>>(deployment,
                            resourceNameList, processDefinitionList);

                } , Collectors.toList()));

        return deploymentThreeTupleList;
    }

    /**
     * 获取流程实例/任务/业务信息列表
     */
    public List<TaskVo> getPersonalTaskList(String userId) {
        User user = userMapper.selectByPrimaryKey(userId);

        // 如果是组任务 使用组任务查询 否则使用普通任务查询
        List<Task> taskList = null;
        if (user.getRole().equals(Constant.ROLE_ACCOUNTING)) {
            // 会计角色是组任务
            taskList = taskService.createTaskQuery().taskCandidateUser(userId).orderByTaskCreateTime().desc().list();
        } else {
            // 其他角色是个人任务
            taskList = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list();
        }

        List<TaskVo> taskVoList = taskList.stream().collect(Collectors.mapping(task -> {

            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId()).singleResult();

            ReimbursementBusiness reimbursementBusiness = reimbursementBusinessMapper
                    .selectByPrimaryKey(processInstance.getBusinessKey());

            List<Comment> commentList = taskService.getProcessInstanceComments(processInstance.getId());

            return new TaskVo(processInstance, task, reimbursementBusiness, commentList, user);

        } , Collectors.toList()));

        return taskVoList;
    }

    public List<HistoricTaskVo> getPersonalHistoryTaskList(String userId) {
        List<HistoricTaskInstance> historicTaskList = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(userId).orderByTaskCreateTime().desc().list();

        List<HistoricTaskVo> historicTaskVoList = historicTaskList.stream()
                .collect(Collectors.mapping(historicTaskInstance -> {

                    HistoricProcessInstance historicProcessInstance = historyService
                            .createHistoricProcessInstanceQuery()
                            .processInstanceId(historicTaskInstance.getProcessInstanceId()).singleResult();

                    ReimbursementBusiness reimbursementBusiness = reimbursementBusinessMapper
                            .selectByPrimaryKey(historicProcessInstance.getBusinessKey());

                    List<Comment> commentList = taskService.getProcessInstanceComments(historicProcessInstance.getId());

                    User user = userMapper.selectByPrimaryKey(userId);

                    return new HistoricTaskVo(historicProcessInstance, historicTaskInstance, reimbursementBusiness,
                            commentList, user);

                } , Collectors.toList()));

        return historicTaskVoList;
    }

    /**
     * 提交一个报销申请
     */
    public void submitReimbursement(String userId, ReimbursementVo reimbursementVo) {
        ReimbursementBusiness reimbursementBusiness = new ReimbursementBusiness();
        BeanUtils.copyProperties(reimbursementVo, reimbursementBusiness);

        // 插入业务数据
        String businessKey = Constant.RS_DB_ID_KEY + UUID.randomUUID().toString().replace("-", "").toUpperCase();
        reimbursementBusiness.setId(businessKey);
        reimbursementBusiness.setCreatePerson(userId);
        reimbursementBusiness.setCreateTime(new Date());
        reimbursementBusiness.setStatus(Constant.DB_STATUS_ONGOING);
        reimbursementBusinessMapper.insert(reimbursementBusiness);

        // 正常来说 可以有两种方式开始流程 第一种是此阶段只插入业务表 不开始流程 待用户确认之后开始流程 或者废弃此业务
        // 也可以直接开始流程 流程的第一个办理者是用户自己 让用户开始流程 此处使用这种
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put(Constant.ACT_ASSIGNEE, userId);
        variables.put(Constant.ACT_REIMBURSEMENT_CHARGES, reimbursementVo.getAmount());
        runtimeService.startProcessInstanceByKey(Constant.RS_KEY, businessKey, variables);
    }

    /**
     * 报销申请第一个Task 由发起者自己完成任务
     * 
     * @param userId
     *            当前程序员用户id
     * @param taskId
     *            要完成的任务id
     * @param message
     *            批注
     */
    public void reimbursementSubmiterCompleteTask(String userId, String taskId, String message) {
        // 获取报销费用
        Integer amount = (Integer) taskService.getVariable(taskId, Constant.ACT_REIMBURSEMENT_CHARGES);

        // 构造流程变量 指定下一个办理人 根据业务信息中的报销费用
        Map<String, Object> variables = new HashMap<String, Object>();
        if (amount >= 500) {
            // 设置待办人 总经理
            variables.put(Constant.ACT_ASSIGNEE, userService.getAllManagerUserIdStr());
        } else {
            // 设置待办人组 会计组
            variables.put(Constant.ACT_ASSIGNEES, userService.getAllAccountingUserIdStr());
        }

        // 设置批注
        User user = userMapper.selectByPrimaryKey(userId);
        Authentication.setAuthenticatedUserId(user.getName());
        String processInstanceId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
        taskService.addComment(taskId, processInstanceId, message);

        // 完成任务
        taskService.complete(taskId, variables);
    }

    /**
     * 财务审批
     * 
     * @param userId
     *            当前财务用户id
     * @param taskId
     *            财务要审批的任务id
     * @param exceptionBill
     *            当前任务是否是异常任务
     * @param accept
     *            是否接受报销
     * @param message
     *            批注
     */
    public void reimbursementAccountingCompleteTask(String userId, String taskId, boolean exceptionBill, boolean accept,
            String message) {
        // 基础参数
        String processInstanceId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
        String businessKey = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId)
                .singleResult().getBusinessKey();

        // 拾取任务
        taskService.claim(taskId, userId);

        Map<String, Object> variables = new HashMap<String, Object>();
        if (exceptionBill == true) {
            // 异常报销
            variables.put(Constant.ACT_REIMBURSEMENT_EXCEPTION_BILL, true);

            // 设置待办人 - 总经理
            String managerId = userService.getAllManagerUserIdStr();
            variables.put(Constant.ACT_ASSIGNEE, managerId);
        } else {
            taskService.setVariable(taskId, Constant.ACT_REIMBURSEMENT_EXCEPTION_BILL, false);
            if (accept == true) {
                // 非异常同意报销 - 流程结束
                variables.put(Constant.ACT_AGREE, true);

                // 设置业务状态为已结束 并且设置报销结果
                ReimbursementBusiness reimbursementBusiness = new ReimbursementBusiness();
                reimbursementBusiness.setId(businessKey);
                reimbursementBusiness.setStatus(Constant.DB_STATUS_ENDED);
                reimbursementBusiness.setResult(accept ? Constant.DB_STATUS_ACCEPT : Constant.DB_STATUS_REFUSED);
                reimbursementBusinessMapper.updateByPrimaryKeySelective(reimbursementBusiness);
            } else {
                // 非异常拒绝报销 流程结束
                variables.put(Constant.ACT_AGREE, false);

                // 设置业务状态为已结束
                ReimbursementBusiness reimbursementBusiness = new ReimbursementBusiness();
                reimbursementBusiness.setId(businessKey);
                reimbursementBusiness.setStatus(Constant.DB_STATUS_ENDED);
                reimbursementBusiness.setResult(accept ? Constant.DB_STATUS_ACCEPT : Constant.DB_STATUS_REFUSED);
                reimbursementBusinessMapper.updateByPrimaryKeySelective(reimbursementBusiness);
            }
        }

        // 设置批注
        User user = userMapper.selectByPrimaryKey(userId);
        Authentication.setAuthenticatedUserId(user.getName());
        taskService.addComment(taskId, processInstanceId, message);

        // 完成任务
        taskService.complete(taskId, variables);
    }

    /**
     * 经理审批
     * 
     * @param userId
     *            当前经理用户id
     * @param taskId
     *            要审批的任务id
     * @param accept
     *            是否同意报销
     * @param message
     *            批注
     */
    public void reimbursementManagerCompleteTask(String userId, String taskId, boolean accept, String message) {
        // 基础参数
        String processInstanceId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
        String businessKey = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId)
                .singleResult().getBusinessKey();

        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put(Constant.ACT_AGREE, accept);

        // 设置业务状态为已结束 并且设置报销结果
        ReimbursementBusiness reimbursementBusiness = new ReimbursementBusiness();
        reimbursementBusiness.setId(businessKey);
        reimbursementBusiness.setStatus(Constant.DB_STATUS_ENDED);
        reimbursementBusiness.setResult(accept ? Constant.DB_STATUS_ACCEPT : Constant.DB_STATUS_REFUSED);
        reimbursementBusinessMapper.updateByPrimaryKeySelective(reimbursementBusiness);

        // 设置批注
        User user = userMapper.selectByPrimaryKey(userId);
        Authentication.setAuthenticatedUserId(user.getName());
        taskService.addComment(taskId, processInstanceId, message);

        // 完成任务
        taskService.complete(taskId, variables);
    }

}
